﻿// //   Copyright 2007-2011 Comdiv (F. Sadykov) - http://code.google.com/u/fagim.sadykov/
// //   Supported by Media Technology LTD 
// //    
// //   Licensed under the Apache License, Version 2.0 (the "License");
// //   you may not use this file except in compliance with the License.
// //   You may obtain a copy of the License at
// //    
// //        http://www.apache.org/licenses/LICENSE-2.0
// //    
// //   Unless required by applicable law or agreed to in writing, software
// //   distributed under the License is distributed on an "AS IS" BASIS,
// //   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// //   See the License for the specific language governing permissions and
// //   limitations under the License.
// //   
// //   MODIFICATIONS HAVE BEEN MADE TO THIS FILE

using System;
using System.Collections.Generic;
using Comdiv.QWeb.Binding;
using Comdiv.QWeb.Diagnostics;
using Comdiv.QWeb.Events;
using Comdiv.QWeb.Factory;
using Comdiv.QWeb.Files;
using Comdiv.QWeb.Logging;
using Comdiv.QWeb.Renders;
using Comdiv.QWeb.Security;
using Comdiv.QWeb.Utils;
using Comdiv.QWeb.ViewEngine;

namespace Comdiv.QWeb {
	public class QWebServiceRegistry {
		private static readonly QWebServiceRegistry _default;
		private readonly object appsync = new object();
		private readonly IDictionary<Type, Stack<object>> pool = new Dictionary<Type, Stack<object>>();
		private readonly IDictionary<Type, Type> registry = new Dictionary<Type, Type>();
		private readonly IDictionary<Type, object> singletons = new Dictionary<Type, object>();
		private readonly object sync = new object();
		private IActionAuthorizer _aa;
		private IQWebEventManager _em;
		private IFormAuthenticationProvider _fa;
		private ILogListener _log;
		private IPrincipalSource _ps;
		private IRoleResolver _rr;
		private IQViewCompiler _vc;
		private IQViewFactory _vf;

		static QWebServiceRegistry() {
			_default = new QWebServiceRegistry();
		}

		public QWebServiceRegistry() {
			RegisterService<ITypeLocator, stubTypeLocator>();
			RegisterService<IRoleResolver, simpleRoleResolver>();
			RegisterService<IPrincipalSource, SimplePrincipalSource>();
			RegisterService<IQWebFactory, QWebFactory>();
			RegisterService<IQWebStatistics, QWebStatistics>();
			RegisterService<IActionAuthorizer, DefaultActionAuthorizer>();
			RegisterService<IViewEngine, stubViewEngine>();
			RegisterService<IFileNameResolver, FileNameResolver>();
			RegisterService<IQWebEventManager, QWebEventManager>();
			RegisterService<ILogListener, DefaultApplicationErrorLogger>();
			RegisterService<IActionBinder, DefaultActionBinder>();
			RegisterService<IQViewFactory, QViewFactory>();
			RegisterService<IQViewCompiler, QViewCompiler>();
			RegisterService<IFormAuthenticationProvider, stubFormAuthenticationProvider>();
		}

		public static QWebServiceRegistry Default {
			get { return _default; }
		}


		public ITypeLocator TypeLocator {
			get { return Get<ITypeLocator>(); }
		}

		public IFileNameResolver FileNameResolver {
			get { return Get<IFileNameResolver>(); }
		}

		public IQWebStatistics Statistics {
			get { return Get<IQWebStatistics>(); }
		}

		public IQWebFactory Factory {
			get { return Get<IQWebFactory>(); }
		}

		public IPrincipalSource PrincipalSource {
			get { return _ps ?? Get<IPrincipalSource>(); }
			set { _ps = value; }
		}

		public IRoleResolver RoleResolver {
			get { return _rr ?? Get<IRoleResolver>(); }
			set { _rr = value; }
		}

		public IActionAuthorizer ActionAuthorizer {
			get { return _aa ?? Get<IActionAuthorizer>(); }
			set { _aa = value; }
		}

		public IQWebEventManager Events {
			get { return _em ?? Get<IQWebEventManager>(); }
			set { _em = value; }
		}

		public ILogListener Log {
			get { return _log ?? Get<ILogListener>(); }
			set { _log = value; }
		}

		public IQViewCompiler QViewCompiler {
			get { return _vc ?? Get<IQViewCompiler>(); }
			set { _vc = value; }
		}

		public IQViewFactory QViewFactory {
			get { return _vf ?? Get<IQViewFactory>(); }
			set { _vf = value; }
		}

		public IFormAuthenticationProvider FormAuthenticator {
			get { return _fa ?? Get<IFormAuthenticationProvider>(); }
			set { _fa = value; }
		}

		public void Synchronize() {
			lock (appsync) {
			}
		}

		public object GetApplicationLock() {
			return appsync;
		}

		public void RegisterService<TServicetype, TImplementationtype>()
			where TImplementationtype : TServicetype, new() {
			lock (sync) {
				if (registry.ContainsKey(typeof (TServicetype)) && registry[typeof (TServicetype)] == typeof (TImplementationtype))
					return;
				registry[typeof (TServicetype)] = typeof (TImplementationtype);
				singletons[typeof (TServicetype)] = null;
			}
		}

		public ServiceHandler<TService> Handle<TService>() {
			lock (sync) {
				return new ServiceHandler<TService>(this);
			}
		}

		public TService Get<TService>() {
			lock (sync) {
				if (singletons[typeof (TService)] == null) {
					singletons[typeof (TService)] = GetNew<TService>(false, false);
					if (singletons[typeof (TService)] is IRegistryBound) {
						((IRegistryBound) singletons[typeof (TService)]).SetRegistry(this);
					}
				}
				return (TService) singletons[typeof (TService)];
			}
		}

		public TService GetNew<TService>(bool pooled = true, bool invokeSetRegistry = true) {
			lock (sync) {
				if (pooled && pool.ContainsKey(typeof (TService))) {
					var p = pool[typeof (TService)];
					if (p.Count > 0) {
						return (TService) p.Pop();
					}
				}
				if (registry.ContainsKey(typeof (TService))) {
					var result = registry[typeof (TService)].create<TService>();
					if (result is IRegistryBound && invokeSetRegistry) {
						((IRegistryBound) result).SetRegistry(this);
					}
					return result;
				}
				return default(TService);
			}
		}

		public void Release<TService>(TService obj) {
			lock (sync) {
				if (!pool.ContainsKey(typeof (TService))) {
					pool[typeof (TService)] = new Stack<object>();
				}
				pool[typeof (TService)].Push(obj);
			}
		}

		#region Nested type: ServiceHandler

		public class ServiceHandler<TService> : IDisposable {
			private readonly QWebServiceRegistry registry;

			protected internal ServiceHandler(QWebServiceRegistry registry) {
				this.registry = registry;
				Service = registry.GetNew<TService>(true);
			}

			public TService Service { get; private set; }

			#region IDisposable Members

			public void Dispose() {
				registry.Release(Service);
			}

			#endregion
		}

		#endregion
	}
}